package model.algorithms;

import java.util.ArrayList;
import java.util.List;

import model.config.Config;
import model.framework.*;

public class BestFit extends Algorithm {

	/**
	 * runs the bestFit algorithm
	 */
	public void run(List<Block> blocks, Field field) {

		Config.p("#Blocks: " + blocks.size());
		for (Block block : blocks) {

			Config.p("Placing block: " + block);

			/* get the current field surface */
			int[] fieldSurface = field.getSurface();

			/* build the frames for all rotations */
			List<List<Frame>> frameList = new ArrayList<List<Frame>>();
			frameList.add(this.buildFrames(block.getBlockType(), fieldSurface, 0));
			if (block.getRotations() > 1 && block.getBlockType().getWidth(0) != block.getBlockType().getWidth(1)) {
				frameList.add(this.buildFrames(block.getBlockType(), fieldSurface, 1));
			}

			/*
			 * set minimum heigth on max value of integer so it can never be reached
			 */
			int minSpace = Integer.MAX_VALUE;

			/*
			 * keep a minframe and rotation to store the frame where the block will fit
			 */
			Frame minFrame = null;
			int rotation = -1;

			/* loop through the rotations a block can have */
			for (int rot = 0; rot < block.getRotations(); rot++) {
				int frameListIndex = -1;
				if (frameList.size() == 1) {
					frameListIndex = 0;
				} else {
					frameListIndex = rot % 2;
				}
				for (Frame frame : frameList.get(frameListIndex)) {
					Config.p("walking through frame: " + frame.getFieldx() + "  rotation: " + rot);
					Config.p(frame);

					int[] surfaceBelowBlock = frame.getSurfaceBelowBlockAfterPlacing(block, rot);

					int belowSurface = 0;

					for (int iBlockSurface = 0; iBlockSurface < surfaceBelowBlock.length; iBlockSurface++) {
						belowSurface = belowSurface	+ surfaceBelowBlock[iBlockSurface];
					}

					/* if there's space in the frame */
					int heightAfterPlacing = frame.heightAfterPlacing(block, rot, false);
					if (heightAfterPlacing > 0 && heightAfterPlacing + 3 * belowSurface < minSpace) {
						minSpace = heightAfterPlacing + 3 * belowSurface;
						Config.p("Found a new minspace: " + minSpace);
						/* set minspace and frame */
						minFrame = frame;
						rotation = rot;
					}
				}
			}

			int[] surfaceBelowBlock = minFrame.getSurfaceBelowBlockAfterPlacing(block, rotation);

			int placeY = this.spaceBelowBlockForPlacing(minFrame.getDimensions(), surfaceBelowBlock);

			Config.p("Placing block on " + minFrame.getFieldx() + ", " + placeY);

			block.setX(minFrame.getFieldx());
			block.setY(placeY);
			block.setRotation(rotation);

			/* place the block */
			field.placeBlock(block);

			Config.p(field);
		}
	}

	@Override
	public String toString() {
		return "BestFit";
	}

}